home *** CD-ROM | disk | FTP | other *** search
-
- /* EMM memory support: all algoritims, math and assembly by Dave Stampe */
- /* MAP-EMM Copyright 26/12/93 by Dave Stampe */
-
- /* Written by Dave Stampe, December 1993 */
-
- /* Contact: dstampe@sunee.waterloo.edu */
-
- /*
- This code is part of the VR-386 project, created by Dave Stampe.
- VR-386 is a desendent of REND386, created by Dave Stampe and
- Bernie Roehl. Almost all the code has been rewritten by Dave
- Stampre for VR-386.
-
- Copyright (c) 1994 by Dave Stampe:
- May be freely used to write software for release into the public domain
- or for educational use; all commercial endeavours MUST contact Dave Stampe
- (dstampe@psych.toronto.edu) for permission to incorporate any part of
- this software or source code into their products! Usually there is no
- charge for under 50-100 items for low-cost or shareware products, and terms
- are reasonable. Any royalties are used for development, so equipment is
- often acceptable payment.
-
- ATTRIBUTION: If you use any part of this source code or the libraries
- in your projects, you must give attribution to VR-386 and Dave Stampe,
- and any other authors in your documentation, source code, and at startup
- of your program. Let's keep the freeware ball rolling!
-
- DEVELOPMENT: VR-386 is a effort to develop the process started by
- REND386, improving programmer access by rewriting the code and supplying
- a standard API. If you write improvements, add new functions rather
- than rewriting current functions. This will make it possible to
- include you improved code in the next API release. YOU can help advance
- VR-386. Comments on the API are welcome.
-
- CONTACT: dstampe@psych.toronto.edu
- */
-
-
- // an EMM memory manager utility
-
- // this one HAS a block-based free() function
-
-
- #include <alloc.h>
- #include <dos.h>
- #include <bios.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- #include "xmem.h" // to check types
-
-
- //////////////////// EMM INTERFACE ////////////////
-
- static unsigned EMMversion;
- static unsigned EMMhandle = 0; // careful to check before using!
- static unsigned EMMsegment;
- static unsigned EMMtotpages;
- static unsigned EMMfreepages;
-
- #define EMM 0x67
- #define EMM_STATUS 0x40
- #define EMM_SEG 0x41
- #define EMM_NPAGES 0x42
- #define EMM_ALLOC 0x43
- #define EMM_MAP 0x44
- #define EMM_FREE 0x45
- #define EMM_VERSION 0x46
- #define EMM_MAPALL 0x5000
-
- static union REGS regs;
- static struct SREGS sregs;
-
- static int EMMsetup()
- {
- unsigned i;
-
- char *v = (char far *) _dos_getvect(EMM);
- v = MK_FP(FP_SEG(v), 10);
- if(strnicmp(v , "EMMXXXX0", 8) ) return 0; // no EMM!
-
- regs.h.ah = EMM_STATUS;
- int86(EMM,®s,®s);
- if(regs.h.ah) return 0; // no driver
-
- regs.h.ah = EMM_VERSION;
- int86(EMM,®s,®s);
- EMMversion = regs.h.al;
- if(regs.h.ah) return 0;
- if(EMMversion<0x40) return 0; // not version 4.0!
-
- regs.h.ah = EMM_SEG;
- int86(EMM,®s,®s);
- EMMsegment = regs.x.bx;
- if(regs.h.ah) return 0;
-
- regs.h.ah = EMM_NPAGES;
- int86(EMM,®s,®s);
- EMMtotpages = regs.x.dx;
- EMMfreepages = regs.x.bx;
- if(regs.h.ah) return 0;
-
- return EMMfreepages; // return free EMM, 0 is error
- }
-
-
- int EMMavail() // number of free pages
- {
- regs.h.ah = EMM_NPAGES;
- int86(EMM,®s,®s);
- EMMtotpages = regs.x.dx;
- EMMfreepages = regs.x.bx;
- if(regs.h.ah) return 0; // 0 = none/error
-
- return EMMfreepages;
- }
-
-
- static unsigned EMMalloc(unsigned pages) // grab some pages
- {
- regs.h.ah = EMM_ALLOC;
- regs.x.bx = pages;
- int86(EMM,®s,®s);
- EMMhandle = regs.x.dx;
- return regs.h.ah; // return nonzero if error
- }
-
-
- static int EMMfree() // drop the pages we got
- {
- if(EMMhandle==0) return -1; // none allocated!
-
- regs.h.ah = EMM_FREE;
- regs.x.dx = EMMhandle;
- int86(EMM,®s,®s);
- return regs.h.ah; // return nonzero if error
- }
-
- // map page p to window part w
- // one 16K page only (not used)
- static int EMMmap(unsigned p_page, unsigned w_page)
- {
- regs.h.ah = EMM_MAP;
- regs.h.al = w_page;
- regs.x.bx = p_page;
- int86(EMM,®s,®s);
- return regs.h.ah; // return nonzero if error
- }
-
- static unsigned map[8] = {0,0,1,1,2,2,3,3}; // even bytes are pages
-
- static int allEMMmap(int start) // map WHOLE window at once!
- {
- map[0] = start; // initialize map table
- map[2] = start+1;
- map[4] = start+2;
- map[6] = start+3;
-
- regs.x.ax = EMM_MAPALL; // map all 4 parts of window at once
- regs.x.dx = EMMhandle;
- regs.x.cx = 4;
- regs.x.si = FP_OFF(map);
- sregs.ds = FP_SEG(map);
- int86x(EMM, ®s, ®s, &sregs);
- return regs.h.ah; // return nonzero if error
- }
-
-
- ////////////////// MEMORY BLOCK MANAGER SYSTEM /////////////////
- ///
- // idea: each byte in a table represents fixed block of memory (512 bytes)
- // each byte is offset to next, with the MSB reserved as a "free" flag
- // So we have a maximum memory allocation size of 127 blocks (63.5K).
-
- // free: simply sets "free" flag. An additional step is to check if the
- // next block in the chain is free too, and combine them if the resultant
- // block is small enough.
-
- // alloc: searches for free block by incrementing pointer by byte values
- // when a free block is found, it either slices a chunk off it, or if it
- // is too small, checks to see if the next blocks are free to make a new
- // large block. If not, it finds the next free block and continues.
-
-
- #define FAILS 0xFFFF // returned if alloc fails
-
- typedef unsigned char BYTE;
-
- static BYTE *fbuf; // the block table
-
- static int size = 8192; // records number of blocks;
-
- #define INITM 64 // initial alloc units
-
-
- static reset_block_manager()
- {
- if (fbuf) free(fbuf);
- fbuf = NULL;
- }
-
-
- static int init_block_manager(int blocks) // clears, sets up initial large blocks
- {
- int i;
-
- size = blocks;
-
- fbuf = malloc(size);
- if(fbuf==NULL) return -1;
-
- for(i=0;i<blocks;i++) fbuf[i] = 0xff;
-
- for(i=0;i<blocks-INITM;i+=INITM)
- {
- fbuf[i] = INITM | 128;
- }
- if(i<blocks) fbuf[i] = (blocks - i) | 128;
-
- return 0;
- }
-
-
- static unsigned scan_free_blocks() // returns total free blocks
- {
- unsigned s = 0;
- unsigned i = 0;
-
- while(i<size)
- {
- if ((fbuf[i]&128)==128) s += fbuf[i] & 0x7F;
- i += fbuf[i] & 0x7F;
- }
- return s;
- }
-
-
- static unsigned scan_used_blocks() // returns total blocks allocated
- {
- unsigned s = 0;
- unsigned i = 0;
-
- while(i<size)
- {
- if ((fbuf[i]&128)==0) s += fbuf[i];
- i += fbuf[i] & 0x7F;
- }
- return s;
- }
-
-
- static void free_blocks(unsigned s) // frees memory, compacts with next
- {
- unsigned i, p;
-
- i = fbuf[s]; // record for tests
- fbuf[s] = i | 0x80; // that's it!
- // now compact a wee bit
- if(fbuf[s+i] & 0x80) // is next free too?
- {
- p = fbuf[i+s] & 0x7F; // size of next
- if (i+p<120) // block would be too big: forget it
- {
- fbuf[s] = 0x80 | (p+i); // else make one big block
- }
- }
- }
-
-
-
- unsigned alloc_blocks(unsigned s) // allocate memory. See description
- {
- unsigned p; // block remainder
- unsigned i; // search ptr
- unsigned sacc; // aggregate accumulator
- unsigned saccptr; // aggregate start
-
-
- if(s>127 || s==0) return FAILS; // block too big
-
- i = 0;
- while(i<size) // scan till end
- {
- if( (fbuf[i]&0x80)==0 )
- {
- i += fbuf[i]; // block allocated: move on
- }
- else if( (fbuf[i]&0x7F) >= s) // big enough?
- {
- p = (fbuf[i]&0x7F) - s; // how much left
- if(p) fbuf[i+s] = p | 128; // new free block
- fbuf[i] = s; // alloc block
- return i;
- }
- else // scan to see if contiguous free
- {
- saccptr = i; // record start
- sacc = fbuf[i] & 0x7F; // record size to accum
- while(i<size)
- {
- i += fbuf[i] & 0x7F; // next
- if(fbuf[i] & 0x80) // free?
- {
- sacc += fbuf[i] & 0x7F; // add to total
- if(sacc>=s) // got enough?
- {
- p = sacc - s; // how much left
- if(p) fbuf[saccptr+s] = p | 128; // free block
- fbuf[saccptr] = s; // alloc block
- return saccptr;
- }
- }
- else
- {
- i = saccptr + sacc; // we hit a used block! keep looking
- break;
- }
- }
- }
- }
- return FAILS; // got to end w/o block
- }
-
-
-
-
- ///////////////////// EMM POINTER ACCESS SYSTEM ////////////////
- /// uses a composite pointer, with the segment and offset
- /// fiddled to contain a page number. Handles up to 4 Megs
-
- int EMM_active = 0; // is EMM system operating?
-
- static long EMMpages; // pages allocated
- static long EMMblocksfree; // pages allocated
- static long EMMblocks; // 512-byte blocks allocated
-
-
- static unsigned allocseg = 0xCF00; // will contain "magic" segment base
- static unsigned allocoff = 0; // will conain "magic" offset base
-
- long alloccount = 0; // EMM blocks used <DEBUG>
-
-
- int initEMMalloc(long wanted) // inits system arg is desired pages
- { // returns actual pages available
- unsigned avp;
-
- fprintf(stderr,"MAP-EMM Expanded memory access system for VR-386\n");
- fprintf(stderr," Copyright (c) 1994 by Dave Stampe\n");
- if(EMMsetup()==0)
- {
- fprintf(stderr,"No EMM driver found!\n");
- return 0;
- }
- fprintf(stderr,"EMM driver version: %d.%d\n", EMMversion>>4, EMMversion & 0x0f);
-
- if(wanted>256) wanted = 256; // can only handle 256 pages with coding
- avp = EMMavail(); // take what we can get
- if(wanted>avp) wanted = avp;
-
- EMMpages = wanted; // total pages
- EMMblocks = wanted<<5; // total blocks
- EMMblocksfree = EMMblocks;
-
- if(init_block_manager(EMMblocks) || // startup blocks
- EMMalloc(wanted) )
- {
- fprintf(stderr,"Error: cannot allocate EMM memory!\n");
- return NULL;
- }
- fprintf(stderr,"%d pages (%ldK) available, allocating %ldK\n",avp, ((long)avp)<<4, wanted<<4);
-
- allEMMmap(0); // reset EMM map
-
- allocseg = EMMsegment - 0x0100; // bump segment down so we can use 8 LSB
- allocoff = 0x1000; // compensates for bump-down
-
- EMM_active = 1;
- return wanted; // returns actual pages granted
- }
-
-
-
- void resetEMMalloc() // shut down system
- {
- EMMfree();
- reset_block_manager(); // reset manager
- EMMblocks = 0;
- EMM_active = 0;
- }
-
-
- // allocates memory, makes up "magic" pointer to it
- void *EMMallocp(long n)
- {
- unsigned page, offset;
- long block;
-
- if(!EMM_active) return NULL;
-
- if(n>48000L) return NULL; // cannot access more than 48K for sure
-
- // n += 20000; // STRESS TEST
-
- n = (n+511)>>9; // bump up to block size
- block = alloc_blocks(n);
- if(block==FAILS) return NULL; // not enough blocks!
- EMMblocksfree -= n;
-
- page = block>>5; // compute page, offset
- offset = (block<<9) & 0x00003FFF;
-
- alloccount++;
-
- allEMMmap(page); // map into window
-
- return MK_FP(allocseg | page,
- allocoff + offset - (page<<4) ); // make a pointer into page
- }
-
-
- void EMMfreep(void *p)
- {
- long page, offset;
-
- page = FP_SEG(p) & 0xFF;
- offset = FP_OFF(p) - 0x1000 + page<<4 + page<<14; // true EMM address
- free_blocks(offset>>9);
- }
-
-
-
-
- // WARNING: the access routine checks the external map! if you do any
- // non-mapped access, you gotta reset it! Use this routine:
-
- void restoreEMM()
- {
- if(!EMM_active) return;
- allEMMmap(0); // restore if external EMM mapping used
- }
-
-
-
- //////////////////////////////////////////////////////////
- /// REND386 interface
-
-
- int accessptr(void *p) // makes pointer accessible up to 60K
- {
- unsigned page;
-
- if(!EMM_active) return 0;
- if(FP_SEG(p) < allocseg) return 0; // not in EMM
-
- page = FP_SEG(p) & 0x00FF; // extract EMM page
-
- if (page!=map[0]) // is it accessible now?
- {
- allEMMmap(page); // map WHOLE window at once!
- return page+1; // had to map it.
- }
-
- return 0; // no mapping required
- }
-
-
-
- // the REND386 call: alloc from EMM if possible
- // else do the usual way from DOS
- void *extmalloc(long n)
- {
- void *p = NULL;
-
- if(EMM_active) p = EMMallocp(n); // try to get EMM
- if(p) return p;
-
- return malloc(n); // if not, use MALLOC
- }
-
-
- // frees memory: tests to see if EMM, else
- // does usual heap free
- void extfree(void *p)
- {
- if(EMM_active!=0 && FP_SEG(p)>=allocseg)
- {
- EMMfreep(p);
- return; // NO EMM FREE YET!
- }
- else
- {
- if(FP_SEG(p)<1)
- {
- fprintf(stderr,"ERROR: ATTEMPT TO FREE NULL POINTER!\n");
- exit(0);
- }
- free(p);
- }
- }
-
-
- long EMMheapsize() // EMM left
- {
- return EMMblocksfree<<9;
- }
-
- long EMMheapused() // EMM used so far
- {
- return (EMMblocks-EMMblocksfree)<<9;
- }
-